/// @file ObstacleManager.cpp
/// @brief centrally manages creation, and drawing of obstacles in the flocking system

#include "boost/foreach.hpp"

#include "ObstacleManager.h"
#include "Configuration.h"


ObstacleManager::ObstacleManager(const bool _enableObstacle)
{
    //initialise obstacles from config file
    m_obstacleList = Configuration::initialiseObstacles();

    //set state of obstacle
    m_enableObstacle = _enableObstacle;

    //set initial draw states
    m_drawInfluenceSphere = true;
    m_drawWireframe = false;

    //set initial stats
    m_countOfBoundingHit = 0;
    m_countOfInfluenceHit = 0;
}

ObstacleManager::~ObstacleManager()
{
    //clean up
    std::cout << "ObstacleManager Cleanup" << std::endl;

    for (int i = 0; i < m_obstacleList->size(); i++) delete (*m_obstacleList)[i];

    m_obstacleList->clear();
    delete m_obstacleList;

    std::cout << "ObstacleManager deleted\n" << std::endl;
}

void ObstacleManager::loadGeometry()
{
    //create vbo for obstacle
    ngl::VBOPrimitives* prim = ngl::VBOPrimitives::instance();

    prim->createVBOSphere("obstaclesphere", 1, 16);

}

void ObstacleManager::draw
                    (
                        ngl::TransformStack _txStack,
                        ShaderManager* io_sman,
                        const std::string _shader
                    )
{
    //draw obstacles if obstacle is enabled
    if (m_enableObstacle)
    {
        ngl::VBOPrimitives* prim=ngl::VBOPrimitives::instance();

        //loop through all obstacles
        BOOST_FOREACH(StaticObject* obstacle, *m_obstacleList)
        {
            //draw bounding sphere/obstacle model

            if (m_drawWireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
            _txStack.pushTransform();
            {
                _txStack.setPosition(obstacle->getPosition().m_x, obstacle->getPosition().m_y, obstacle->getPosition().m_z);

                _txStack.setScale(obstacle->getBoundingRadius(), obstacle->getBoundingRadius(), obstacle->getBoundingRadius());

                //update transform and color to shader
                io_sman->updateModelColor(_shader, _txStack.getCurrAndGlobal().getMatrix(), ngl::Colour(1, 0, 0));

                //draw sphere
                prim->draw("cube");
            }
            _txStack.popTransform();
            if (m_drawWireframe) glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);


            //draw influence sphere
            if (m_drawInfluenceSphere)
            {
                glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                _txStack.pushTransform();
                {
                    _txStack.setPosition(obstacle->getPosition().m_x, obstacle->getPosition().m_y, obstacle->getPosition().m_z);

                    _txStack.setScale(obstacle->getInfluenceRadius(), obstacle->getInfluenceRadius(), obstacle->getInfluenceRadius());

                    //update transform and color to shader
                    io_sman->updateModelColor(_shader, _txStack.getCurrAndGlobal().getMatrix(), ngl::Colour(1, 1, 1));

                    //draw sphere
                    prim->draw("obstaclesphere");
                }
                _txStack.popTransform();
                glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
            }
        }
    }

}
